#ifndef _MPSSED_H_
#define _MPSSED_H_

#include <stdint.h>

#ifndef PACKED
#define PACKED __attribute__ ((packed))
#endif

#ifndef INLINE
#define INLINE static inline
#endif

typedef int32_t i32;
typedef int16_t i16;
typedef int8_t  i8;

typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;

#define MPSSED_NEG_WRITE     0x1
#define MPSSED_POS_READ      0x4
#define MPSSED_MODE_BIT      0x2
#define MPSSED_LSB           0x8
#define MPSSED_TDI_SET       0x10
#define MPSSED_TDO_GET       0x20
#define MPSSED_TMS_SET       0x40

#ifndef CLK_POS
/*实现下列宏即可*/
#define TMS_REG_V (0)
#define TDI_REG_V (0)
#define GPIO_OUT_SET(val)
#define TDI_SET
#define TDI_CLR
#define CLK_POS
#define CLK_NEG
#define TDO_GET (0)
#define SET_PIN_DIR(ish,pin,dir) (0)
#define GET_PIN_STS(ish)     (0)
#define DELAY_TIM       (0);
#define GPIOL1_VAL      (0)
#define CLK_STS         (0)
#endif


#define OUT_SET(val)    GPIO_OUT_SET(out_reg_val<<(!(val)*16))
#define GET_SENDBUF     (sendBuf+sendBuf_write_pos)

extern u8 byteMSB[0x100];
extern u8 byteLSB[0x100];
extern u8 sendBuf[1024];
extern int sendBuf_write_pos;
extern int loopback;
extern int div5;
extern int period;
extern int send_usb(u8*data,int len);
extern int send_err(u8 cmd);
extern int send_usb_proc();

/*
命令与方向
        (IN)        (OUT)       (IN CLK)    (OUT CLK)       (mode)
-----------------------------------------------------------------
MSB
0x10                o                       +ve             byte
0x11                o                       -ve             byte
0x12                o                       +ve             bit
0x13                o                       -ve             bit
0x20    o                       +ve                         byte
0x24    o                       -ve                         byte
0x22    o                       +ve                         bit
0x26    o                       -ve                         bit
0x31    o           o           +ve         -ve             byte
0x34    o           o           -ve         +ve             byte
0x33    o           o           +ve         -ve             bit
0x36    o           o           -ve         +ve             bit
-------------------------------------------------------------------
LSB
0x18                o                       +ve             byte
0x19                o                       -ve             byte
0x1a                o                       +ve             bit
0x1b                o                       -ve             bit
0x28    o                       +ve                         byte
0x2c    o                       -ve                         byte
0x2a    o                       +ve                         bit
0x2e    o                       -ve                         bit
0x39    o           o           +ve         -ve             byte
0x3c    o           o           -ve         +ve             byte
0x3b    o           o           +ve         -ve             bit
0x3e    o           o           -ve         +ve             bit

0x4a                o                       +VE             bit
0x4b                o                       -VE             bit
0x6a    o           o           +ve         -ve             bit
0x6b    o           o           -ve         +ve             bit
0x6c    o           o           +ve         -ve             bit
0x6d    o           o           -ve         -ve             bit



*/

INLINE int MPSSED_ProcessBit(u8*cmd){
    int len = cmd[1];
    u8 _cmd_ = *cmd;
    u8 *send_base = GET_SENDBUF;
    u8 *send_ptr = GET_SENDBUF;
    len++;
    if(!(_cmd_&MPSSED_MODE_BIT)){
        len |= cmd[2]<<8;
        len *= 8;
        cmd += 3;
    }
    else{
        if(len>8)len = 8;
        cmd += 2;
    }

    DELAY_TIM;
    DELAY_TIM;

    u8  byte = *cmd;
    u8  *pSB = byteLSB;
    u8  *pSB_out = byteMSB;         //实际输入是 tdo_val |= (tdo_val<<1) | tdo

    if(!(_cmd_&MPSSED_LSB)){
        pSB = byteMSB;      //交换高低位
        pSB_out = byteLSB;
    }
    byte = pSB[byte];

    u8 tdo_val = 0;
    int count = 0;
    u32 out_reg_val = 0;            //可能是tdo,也可能是tms
    if(_cmd_&MPSSED_TMS_SET){
        out_reg_val=TMS_REG_V;
    }
    else{
        out_reg_val=TDI_REG_V;
    }

    /*
    在OUT_POS_IN_NEG中的时序如下

    111: 表示输出位数
    xxx: 表示可改变
    |   |-|  |+|  |-|  |+|  |-|  |+|  |-|  |+|  |-|  |+|  |-|    VE      (+ve或-ve)
    |____      ____      ____      ____      ____      ____
    |    \____/    \____/    \____/    \____/    \____/    \_    CLK        (主时钟输出)
    --------------------------------------------------------------------------------------
    |下面为推荐时序
    |          ____      ____      ____      ____      _
    |_________/    \____/    \____/    \____/    \____/     实际输出TCK      (初始化为低)
    |--xxxxxx0000xxxxxx1111xxxxxx2222xxxxxx3333xxxxxxxxx    TDO     (+ve)    输入到mcu中
    |xx-----xxxxx00000xxxxx11111xxxxx22222xxxxx33333xxxxx   TDI     (-ve)    mcu输出
    ------------------------------------------------------------------------------------
    |___       ____      ____      ____      ____      _
    |   \_____/    \____/    \____/    \____/    \____/     实际输出TCK      (初始化为高)
    |xx0000xxxxxxx1111xxxxxx2222xxxxxx3333xxxxxx4444xxxxxx  TDO     (-ve)    输入到mcu中
    |xxxxxxx00000xxxxx11111xxxxx22222xxxxx33333xxxxxx44444  TDI     (+ve)    mcu输出

    当前源码实现的时序如下
    |        |P|  |N|  |P|  |N|  |P|  |N|  |P|  |N|  |P|  |P|   |E|         MCU针对TCK的操作,P:置位,N:清位,E:结束
    |          ____      ____      ____      ____      _____
    |_________/    \____/    \____/    \____/    \____/     \__________     TCK(默认为低)
    |______________      ____      ____      ____      _____      _____
    |              \____/    \____/    \____/    \____/     \____/          TCK(默认为高)

    */
    int clk_sts = CLK_STS;

#define OUT_NEG_IN_NEG      \
        OUT_SET(byte&1);    \
        tdo_val |= TDO_GET; \
        DELAY_TIM           \
        CLK_POS;            \
        DELAY_TIM;          \
        CLK_NEG;            \

#define OUT_NEG_IN_POS      \
        OUT_SET(byte&1);    \
        DELAY_TIM;          \
        CLK_POS;            \
        tdo_val |= TDO_GET; \
        DELAY_TIM;          \
        CLK_NEG;

#define OUT_POS_IN_NEG      \
        CLK_POS;            \
        OUT_SET(byte&1);    \
        DELAY_TIM;          \
        CLK_NEG;            \
        tdo_val |= TDO_GET; \
        DELAY_TIM;          \

#define OUT_POS_IN_POS      \
        CLK_POS;            \
        OUT_SET(byte&1);    \
        tdo_val |= TDO_GET; \
        DELAY_TIM;          \
        CLK_NEG;            \
        DELAY_TIM;          \

#define OUT_NEG             \
        OUT_SET(byte&1);    \
        DELAY_TIM;          \
        CLK_POS;            \
        DELAY_TIM;          \
        CLK_NEG;            \

#define OUT_POS             \
        CLK_POS;            \
        OUT_SET(byte&1);    \
        DELAY_TIM;          \
        CLK_NEG;            \
        DELAY_TIM;          \

#define IN_NEG              \
        CLK_POS;            \
        DELAY_TIM;          \
        CLK_NEG;            \
        tdo_val |= TDO_GET; \
        DELAY_TIM;          \

#define IN_POS              \
        CLK_POS;            \
        tdo_val |= TDO_GET; \
        DELAY_TIM;          \
        CLK_NEG;            \
        DELAY_TIM;          \


#define WRITE_OUT                                   \
        count++;                                    \
        if(count>=8){                               \
            count = 0;                              \
            *send_ptr++ = pSB_out[(tdo_val)&0xff];    \
            tdo_val = 0;                        \
            cmd++;					            \
            byte = pSB[*cmd];                   \
        }

#define NO_WRITE_OUT    \
        count++;        \
        if(count>=8){   \
            count = 0;  \
            cmd++;          \
            byte = pSB[*cmd];\
        }



#define BIT_MODE_PROC(P,W)      \
    while(len>0){               \
        len--;                  \
        P/* OUT_NEG_IN_NEG;*/   \
        byte>>=1;               \
        W /* WRITE_OUT; */      \
        tdo_val <<= 1;          \
    }

#define BYTE_MODE_PROC BIT_MODE_PROC        /*暂时共用一个.实际上是相同的*/

    int mode = _cmd_ &~0x8;
    if(mode>0x40){
        //输出为TMS
    }
    switch (mode)
    {
        case 0x10:{BYTE_MODE_PROC(OUT_POS,NO_WRITE_OUT);}break;
        case 0x11:{BYTE_MODE_PROC(OUT_NEG,NO_WRITE_OUT);}break;
        case 0x12:{ BIT_MODE_PROC(OUT_POS,NO_WRITE_OUT);}break;
        case 0x13:{ BIT_MODE_PROC(OUT_NEG,NO_WRITE_OUT);}break;
        case 0x20:{BYTE_MODE_PROC(IN_POS ,WRITE_OUT);}break;
        case 0x24:{BYTE_MODE_PROC(IN_NEG ,WRITE_OUT);}break;
        case 0x22:{ BIT_MODE_PROC(IN_POS ,WRITE_OUT);}break;
        case 0x26:{ BIT_MODE_PROC(IN_NEG ,WRITE_OUT);}break;

        case 0x31:{BYTE_MODE_PROC(OUT_NEG_IN_POS,WRITE_OUT);}break;
        case 0x34:{BYTE_MODE_PROC(OUT_POS_IN_NEG,WRITE_OUT);}break;
        case 0x33:{ BIT_MODE_PROC(OUT_NEG_IN_POS,WRITE_OUT);}break;
        case 0x36:{ BIT_MODE_PROC(OUT_POS_IN_NEG,WRITE_OUT);}break;

    default:
		{
            //第7位会被当成设置TDI/DO状态.
            if(byte&0x80){
                TDI_SET;
            }
            else{
                TDI_CLR;
            }
            if(len>7) len = 7;      //TMS只处理6位
            /*
            手册上的表格有一些小小的问题.
            TMS传输时.应该是在-ve是传输第一个数据
            */
			switch(_cmd_){
				case 0x4a:{BYTE_MODE_PROC(OUT_POS,NO_WRITE_OUT);}break;
				case 0x4b:{BYTE_MODE_PROC(OUT_NEG,NO_WRITE_OUT);}break;

				case 0x6a:{ BIT_MODE_PROC(OUT_POS_IN_POS,WRITE_OUT);}break;
				case 0x6b:{ BIT_MODE_PROC(OUT_NEG_IN_POS,WRITE_OUT);}break;
				case 0x6e:{ BIT_MODE_PROC(OUT_POS_IN_NEG,WRITE_OUT);}break;
				case 0x6f:{ BIT_MODE_PROC(OUT_NEG_IN_NEG,WRITE_OUT);}break;
				default:break;
			}
		}
        break;
    }

    if(clk_sts){
        //空闲时的CLK
        CLK_POS;
    }

    //处理TDI数据输入
    if(_cmd_&MPSSED_TDO_GET){
    	if(count){
            /*
            不需要补全位数.
            但实际接收时是从MSB接收.所以需要把高低位互换.
                如4b 00 00.
                    接收1bit. 0x01  顺序(1.......)
                    则需要变为0x80
                  4b 06 00
                    接收7bit , 0x07     (0000111.)
                    则变为0xE0          0xe0

            可以写成另一种代码
                实际上相当于 (counter从0~7,8位)
                    tdo_val |= tdi << (counter);
                    结束后，剩余位处理
                    while(counter<8)
                        tdo_val <<= 1;
                        counter++;
            */
            #if 0
            while(1){
                /*需要补全数据位*/
                count++;
                if(count>=8){
                    break;
                }
                tdo_val <<= 1;
            }
            #endif
            tdo_val >>= 1;
			*send_ptr = pSB_out[tdo_val];
			send_ptr++;
    	}
        send_usb(sendBuf,send_ptr - send_base);
    }
    return 0;
}

#define CHECK_BUF_LEN(_len_) if(_len_>cmd_len) return -(_len_); result = _len_;

INLINE int MPSSED_ProcessCmd(u8*cmd,int cmd_len){
    u8 _cmd_ = *cmd;
    int result = 1;     //最少是1个字节
    if(_cmd_>=0x80){
        if(_cmd_<0x84){
            if(_cmd_ & 1){
                CHECK_BUF_LEN(1);
                //读取
                u8 sts = GET_PIN_STS(_cmd_&0x2);
                sendBuf[0] = sts;
                send_usb(sendBuf,1);
            }
            else{
                CHECK_BUF_LEN(3);
                //设置方向
                u8 dir = cmd[2];
                u8 pin = cmd[1];
                SET_PIN_DIR((_cmd_&0x2),pin,dir);
            }
        }
        else{
            switch (_cmd_)
            {
            case 0x84:
            case 0x85:{
                loopback = !(0x85-0x84);
            }break;

            case 0x86:{
                CHECK_BUF_LEN(3);
                //div5是向后兼容的.
                u16 tck_div = cmd[1]|(cmd[2]<<8);
                period = (60000000 / div5) / ((1+tck_div)*2);
            }break;

            case 0x8B:
            case 0x8A:
            {
                div5 = 1 + (_cmd_-0x8A) * 4;
            }break;

            case 0x9C:
            case 0x9D:
            case 0x8E:
            case 0x8F:{
                int output_bitlen = cmd[1];
                if(_cmd_!=0x8E){
                    CHECK_BUF_LEN(3);
                    output_bitlen += cmd[2]<<8;
                    cmd += 3;
                }
                else{
                    CHECK_BUF_LEN(2);
                    cmd += 2;
                    if(output_bitlen>7)output_bitlen = 7;       //最多8个时钟
                }
                output_bitlen += 1;
                output_bitlen *= (_cmd_ - 0x8E) * 8;

                while(output_bitlen>0){
                    output_bitlen--;
                    CLK_POS;
                    DELAY_TIM;
                    CLK_NEG;
                    if(_cmd_>0x8F){
                        int v = GPIOL1_VAL;
                        int islow = _cmd_-0x9C;
                        v = v ^ islow;
                        if(v){
                            //退出循环
                            break;
                        }
                    }
                    DELAY_TIM;
                }
            }break;

            case 0x87:{
            	//Send Immediate
            	//发送数据
                send_usb_proc();
            }break;

            case 0x94:
            case 0x95:{
                //持续输出时钟.直到GPIOL1或者I/O1 为高(0x94)或者低(0x95). 如果电平又变化为高或者低.又持续输出
            }
            case 0x96:
            case 0x97:{
                //用于适配ARM JTAG的RTCK引脚
                int on = !(_cmd_-0x96);
            }
            case 0x8C:
            case 0x8D:{
                //I2C的数据
            }
            case 0x9E:{     //FT232H only
                //I2C

            }
            default:
                send_err(_cmd_);
                //send_usb(sendBuf,2);
                break;
            }
        }
    }
    else{
        //需要检查长度

        if(!(_cmd_&(MPSSED_TMS_SET|MPSSED_TDI_SET))){
            //没有输出
            if(_cmd_&MPSSED_MODE_BIT){
                //实际上只有2个字节
                CHECK_BUF_LEN(2);
            }
            else{
                //三个字节
                CHECK_BUF_LEN(3);
            }

        }
        else{
            //存在数据输出
            if(_cmd_&MPSSED_MODE_BIT){
                CHECK_BUF_LEN(3);
            }
            else{
                int len = cmd[1] | (cmd[2]<<8);
                //需要额外+1字节
                CHECK_BUF_LEN(3+len+1);
            }
        }

        //if(*cmd&MPSSED_MODE_BIT){
        MPSSED_ProcessBit(cmd);
    }
    return result;
}


#endif
